﻿using System.Text;
using System.Net.Sockets;
using System.Net;
using System;

namespace Protocolo
{
    internal class Comunicacion
    {
        private const int ReceiveTimeout = 5000;

        internal static void EnviarBroadcastUDP(string mensaje, int puertoUDP)
        {
            UdpClient udpClient = null;
            try
            {
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, puertoUDP);
                udpClient = new UdpClient();
                byte[] mensajeAEnviar = Encoding.ASCII.GetBytes(mensaje);
                udpClient.Connect(endpoint);
                udpClient.Send(mensajeAEnviar, mensajeAEnviar.Length);
            }
            catch (Exception ex)
            {
                throw new Exception("Error enviando mensaje UDP: " + ex.Message);
            }
            finally
            {
                if(udpClient != null)
                    udpClient.Close();
            }
        }

        internal static void EnviarMensajeUDP(string mensaje, string ip, int puertoUDP)
        {
            UdpClient udpClient = null;
            try
            {
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), puertoUDP);
                udpClient = new UdpClient();
                byte[] mensajeAEnviar = Encoding.ASCII.GetBytes(mensaje);
                udpClient.Connect(endpoint);
                udpClient.Send(mensajeAEnviar, mensajeAEnviar.Length);
                udpClient.Close();
            }
            catch (Exception ex)
            {
                throw new Exception("Error enviando mensaje UDP: " + ex.Message);
            }
            finally
            {
                if (udpClient != null)
                    udpClient.Close();
            }
        }

        internal static string RecibirMensajeUDP(int puertoUDP, bool timeout)
        {
            UdpClient udpClient = null;
            try
            {
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, puertoUDP);
                IPEndPoint remoteEndPoint = null;
                udpClient = new UdpClient();
                udpClient.Client.ReceiveTimeout = timeout ? ReceiveTimeout : 0;
                udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                udpClient.Client.Bind(endpoint);

                byte[] mensajeRecibido = udpClient.Receive(ref remoteEndPoint);

                return Encoding.ASCII.GetString(mensajeRecibido, 0, mensajeRecibido.Length);
            }
            catch (Exception ex)
            {
                throw new Exception("Error recibiendo mensaje UDP: " + ex.Message);
            }
            finally
            {
                if (udpClient != null)
                    udpClient.Close();
            }
        }

        internal static void EnviarMensajeTCP(string mensaje, string ip, int puerto)
        {
            NetworkStream stream = null;
            TcpClient tcpClient = null;
            try
            {
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), puerto);
                tcpClient = new TcpClient();
                tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                tcpClient.Connect(endpoint);

                byte[] mensajeAEnviar = Encoding.ASCII.GetBytes(mensaje);

                stream = tcpClient.GetStream();
                stream.Write(mensajeAEnviar, 0, mensajeAEnviar.Length);
            }
            catch (Exception ex)
            {
                throw new Exception("Error enviando mensaje " + ex.Message);
            }
            finally
            {
                if(stream != null)
                    stream.Close();

                if(tcpClient != null)
                    tcpClient.Close();
            }
        }

        internal static string RecibirMensajeTCP(string ip, int puerto, bool timeout)
        {
            TcpListener tcpListener = null;
            NetworkStream stream = null;
            TcpClient tcpClient = null;
            
            try
            {
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse(ip), puerto);
                tcpListener = new TcpListener(endpoint);
                tcpListener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                tcpListener.Start();
                               
                tcpClient = tcpListener.AcceptTcpClient();
                tcpClient.ReceiveTimeout = timeout ? ReceiveTimeout : 0;

                stream = tcpClient.GetStream();

                string mensajeRecibido = string.Empty;
                byte[] bytes = new byte[256];
                int bytesLeidos = 0;
                while ((bytesLeidos = stream.Read(bytes, 0, bytes.Length)) != 0)
                {
                    mensajeRecibido += Encoding.ASCII.GetString(bytes, 0, bytesLeidos);
                }
                
                return mensajeRecibido;
            }
            catch (Exception ex)
            {
                throw new Exception("Error recibiendo mensaje TCP: " + ex.Message);
            }
            finally
            {
                if(tcpListener != null)
                    tcpListener.Stop();
                
                if (stream != null)
                    stream.Close();

                if (tcpClient != null)
                    tcpClient.Close();
            }
        }
    }
}
